package com.dayu.tcp.service.client;

import com.dayu.tcp.logging.Log;
import com.dayu.tcp.logging.LogFactory;
import com.dayu.tcp.service.EventDispatcher;
import com.dayu.tcp.service.WrappedChannel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.NonNull;

import java.io.IOException;

public class ClientDispatchHandler extends ChannelInboundHandlerAdapter {

    private static final Log log = LogFactory.getLog(ClientDispatchHandler.class);

    private final EventDispatcher eventDispatcher;

    public ClientDispatchHandler(@NonNull EventDispatcher eventDispatcher) {
        this.eventDispatcher = eventDispatcher;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("Message received from channel '{" + ctx.channel().id().asShortText() + "}' : '{" + msg.toString() + "}'.");
        }
        WrappedChannel channel = ((BaseClient) eventDispatcher.getService()).getChannel();
        eventDispatcher.dispatchMessageEvent(ctx, channel, msg);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("Connected on channel '{" + ctx.channel().id().asShortText() + "}'.");
        }
        BaseClient baseClient = (BaseClient) eventDispatcher.getService();
        WrappedChannel channel = baseClient.getChannel();
        if (channel == null) {
            baseClient.setChannel(new WrappedChannel(ctx.channel()));
        }
        eventDispatcher.dispatchChannelEvent(ctx, channel);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        closeChanel(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        BaseClient baseClient = (BaseClient) eventDispatcher.getService();
        WrappedChannel channel = baseClient.getChannel();
        if (channel != null) {
            eventDispatcher.dispatchExceptionCaught(ctx, channel, cause);
        }
        if (cause instanceof IOException) {
            ctx.close();
            closeChanel(ctx);
        }
    }

    private void closeChanel(ChannelHandlerContext ctx) {
        BaseClient baseClient = (BaseClient) eventDispatcher.getService();
        WrappedChannel channel = baseClient.getChannel();
        if (channel != null) {
            baseClient.setChannel(null);
            if (log.isDebugEnabled()) {
                log.debug("Channel '{" + channel.id().asShortText() + "}' was closed.");
            }
        }
        eventDispatcher.dispatchChannelEvent(ctx, channel);
    }
}
